package flexconsole.view {
	import flash.desktop.NativeApplication;
	import flash.events.Event;
	import flash.events.TextEvent;
	import flash.system.System;
	
	import flexconsole.*;
	import flexconsole.controls.FeedbackBox;
	import flexconsole.events.*;
	import flexconsole.model.*;
	import flexconsole.utils.LogXMLUtil;
	
	import flexunit.framework.Assert;
	
	import mx.events.DividerEvent;
	import mx.events.PropertyChangeEvent;
	import mx.logging.ILogger;
	import mx.logging.Log;
	import mx.utils.StringUtil;
	
	import org.puremvc.as3.interfaces.INotification;
	import org.puremvc.as3.patterns.mediator.Mediator;
	
	public class AppMediator extends Mediator {
		
		static private var logger:ILogger = Log.getLogger("flexconsole.view.AppMediator");
		
		protected var windowStateModel:WindowStateModel;
		
		private var isViewDirty:Boolean = false;
		
		public function AppMediator(mediatorName:String = null, viewComponent:Object = null) {
			super(mediatorName, viewComponent);
		}
		
		public function get view():FlexConsole {
			return viewComponent as FlexConsole;
		}
		
		public function get appFacade():AppFacade {
			return facade as AppFacade;
		}
		
		override public function onRegister():void {
			logger.debug("onRegister()");
			super.onRegister();
			Assert.assertNotNull(appFacade);
			Assert.assertNotNull(view);
			//   Register view mediators
			appFacade.registerMediator(new FilterControlsMediator(AppFacade.MEDIATORNAME_FILTERCONTROLS, view.filterControls));
			appFacade.registerMediator(new GridMediator(AppFacade.MEDIATORNAME_GRID, view.grid));
			appFacade.registerMediator(new ToolbarMediator(AppFacade.MEDIATORNAME_TOOLBAR, view.toolbar));
			appFacade.registerMediator(new PreferenceMediator(AppFacade.MEDIATORNAME_PREFERENCE, view.preference));
			//   Initialize view
			windowStateModel = new WindowStateModel(appFacade.configProxy.getValue(ConfigKeys.WINDOW_STATE_APP, null), view.stage.nativeWindow);
			windowStateModel.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, onWindowStatePropertyChange);
			view.dividedbox.addEventListener(DividerEvent.DIVIDER_RELEASE, onDividerEvent);
			NativeApplication.nativeApplication.addEventListener(Event.EXITING, onNativeApplicationExiting);
			//   catch all event handler
			view.addEventListener(CategoryEvent.OPEN_CHANGE, onCategoryEvent);
			view.addEventListener(CategoryEvent.SELECTION_CHANGE, onCategoryEvent);
			view.addEventListener(CategoryEvent.REMOVE_ALL, onCategoryEvent);
			view.addEventListener(CategoryEvent.REMOVE, onCategoryEvent);
			view.addEventListener(LogLevelEvent.LOG_LEVEL_CHANGE, onLogLevelEvent);
			view.addEventListener(ConnectionEvent.CONNECT, onConnectionEvent);
			view.addEventListener(ConnectionEvent.DISCONNECT, onConnectionEvent);
			view.addEventListener(FilterVisibleEvent.SHOW, onFilterVisibleEvent);
			view.addEventListener(FilterVisibleEvent.HIDE, onFilterVisibleEvent);
			view.addEventListener(KeywordEvent.KEYWORD, onKeywordEvent);
			view.addEventListener(LogMessageEvent.REMOVE_ALL, onLogMessageEvent);
			view.addEventListener(LogMessageEvent.REMOVE, onLogMessageEvent);
			view.addEventListener(LogMessageEvent.INSERT_MARKER, onLogMessageEvent);
			view.addEventListener(LogMessageEvent.COPY, onLogMessageEvent);
			view.addEventListener(TextEvent.LINK, onTextEvent);
			view.addEventListener(PreferenceEvent.OPEN, onPreferenceEvent);
			view.addEventListener(ScrollLockEvent.LOCK, onScrollLockEvent);
            view.addEventListener(ScrollLockEvent.UNLOCK, onScrollLockEvent);
			//   don't invalidate, update now, avoids a screen update lag
			updateView();
		}
		
		override public function listNotificationInterests():Array {
			return [ AppFacade.DATA_CHANGE ];
		}
		
		override public function handleNotification(notification:INotification):void {
			if (AppFacade.PROXYNAME_CONFIG == notification.getType()) {
				if (notification.getBody() == null) {
					// fill refresh
					invalidateView();
				} else {
					switch (notification.getBody()) {
						case ConfigKeys.WINDOW_STATE_APP:
						case ConfigKeys.FILTER_VISIBLE:
							invalidateView();
					}
				}
			}
		}
		
		protected function invalidateView():void {
			if (view && !isViewDirty) {
				isViewDirty = true;
				view.callLater(updateView);
			}
		}
		
		protected function onFilterVisibleEvent(event:FilterVisibleEvent):void {
			appFacade.configProxy.setValue(ConfigKeys.FILTER_VISIBLE, event.type == FilterVisibleEvent.SHOW);
		}
		
		protected function onConnectionEvent(event:ConnectionEvent):void {
			var bool:Boolean = event.type == ConnectionEvent.CONNECT;
			appFacade.configProxy.setValue(ConfigKeys.CONNECTED, bool);
			sendNotification(AppFacade.CONNECTION, bool);
		}
		
		protected function onNativeApplicationExiting(event:Event):void {
			logger.debug("onNativeApplicationExiting({0})", event);
			sendNotification(AppFacade.SHUTDOWN);
		}
		
		protected function onWindowStatePropertyChange(event:PropertyChangeEvent):void {
			logger.debug("onWindowStatePropertyChange({0})", event);
			appFacade.configProxy.setValue(ConfigKeys.WINDOW_STATE_APP, windowStateModel.write());
		}
		
		protected function onCategoryEvent(event:CategoryEvent):void {
			logger.debug("onCategoryChange({0})", event);
			var type:String = event.type;
			var categoryProxy:ICategoryProxy = appFacade.categoryProxy;
			
			if (type == CategoryEvent.SELECTION_CHANGE) {
				categoryProxy.select(event.item, event.state);
			} else if (type == CategoryEvent.OPEN_CHANGE) {
				categoryProxy.open(event.item, event.state);
			} else if (type == CategoryEvent.REMOVE) {
				categoryProxy.remove(event.item);
			} else if (type == CategoryEvent.REMOVE_ALL) {
				categoryProxy.clear();
			} else {
				var err:Error = new Error("Cannot process CategoryChangeEvent of type: " + event.type);
				logger.error(err.message);
				throw err;
			}
		}
		
		protected function onLogLevelEvent(event:LogLevelEvent):void {
			logger.debug("onLogLevelChange({0})", event);
			var configProxy:IConfigProxy = appFacade.configProxy;
			var model:LogLevelModel = new LogLevelModel(configProxy.getValue(ConfigKeys.FILTER_LOG_LEVELS, null));
			
			switch (event.logLevel) {
				case LogLevelModel.DEBUG:
					model.debug = event.state;
					break;
				case LogLevelModel.INFO:
					model.info = event.state;
					break;
				case LogLevelModel.WARN:
					model.warn = event.state;
					break;
				case LogLevelModel.ERROR:
					model.error = event.state;
					break;
				case LogLevelModel.FATAL:
					model.fatal = event.state;
					break;
			}
			configProxy.setValue(ConfigKeys.FILTER_LOG_LEVELS, model.write());
		
		}
		
		protected function onKeywordEvent(event:KeywordEvent):void {
			logger.debug("onKeyword({0})", event);
			appFacade.configProxy.setValue(ConfigKeys.FILTER_KEYWORD, event.keyword);
		
		}
		
		protected function onLogMessageEvent(event:LogMessageEvent):void {
			logger.debug("onLogMessageEvent({0})", event);
			var type:String = event.type;
			var logMessageProxy:ILogMessageProxy = appFacade.logMessageProxy;
			var messages:Array = event.messages ? event.messages : [];
			var i:int = messages.length;
			
			try {
				if (type == LogMessageEvent.REMOVE_ALL) {
					logMessageProxy.clear();
					return;
				} else if (!i) {
					throw new Error("No messages found");
				}
				
				if (type == LogMessageEvent.REMOVE) {
					while (i--) {
						logMessageProxy.remove(messages[i] as XML);
					}
				} else if (type == LogMessageEvent.COPY) {
					var output:Array = new Array();
					
					while (i--) {
						output.unshift(LogXMLUtil.fromXML(messages[i] as XML));
					}
					System.setClipboard(output.join("\n"));
					FeedbackBox.show(StringUtil.substitute(appFacade.resourceBundle.copiedNLogs, output.length));
				} else if (type == LogMessageEvent.INSERT_MARKER) {
					logMessageProxy.insertMarker(messages[0]);
				} else {
					throw new Error("Cannot process event of type: " + event.type);
				}
			} catch (e:Error) {
				logger.error(e.message);
				throw e;
			}
		
		}
		
		protected function onDividerEvent(event:DividerEvent):void {
			var configProxy:IConfigProxy = appFacade.configProxy;
			var width:Number = Math.max(0, view.filterControls.width + event.delta);
			var filterVisible:Boolean = configProxy.getValue(ConfigKeys.FILTER_VISIBLE, true);
			configProxy.setValue(ConfigKeys.FILTER_PANEL_WIDTH, width);
			
			if (width == 0 && filterVisible) {
				configProxy.setValue(ConfigKeys.FILTER_VISIBLE, false);
			} else if (width > 0 && !filterVisible) {
				configProxy.setValue(ConfigKeys.FILTER_VISIBLE, true);
			}
		}
		
		protected function onTextEvent(event:TextEvent):void {
			if (event.text == "help") {
				sendNotification(AppFacade.HELP);
			}
		}
		
		protected function onPreferenceEvent(event:PreferenceEvent):void {
			sendNotification(AppFacade.PREFERENCE);
		}
		
		protected function onScrollLockEvent(event:ScrollLockEvent):void {
			appFacade.configProxy.setValue(ConfigKeys.SCROLL_LOCK, event.type == ScrollLockEvent.LOCK);
		}
		
		
		protected function updateView():void {
			logger.debug("updateView()");
			isViewDirty = false;
			var configProxy:IConfigProxy = appFacade.configProxy;
			var obj:Object = configProxy.getValue(ConfigKeys.WINDOW_STATE_APP, null);
			
			if (obj) {
				windowStateModel.read(obj);
				windowStateModel.updateTarget();
			}
			var filterVisible:Boolean = configProxy.getValue(ConfigKeys.FILTER_VISIBLE, true);
			var filterWidth:Number = configProxy.getValue(ConfigKeys.FILTER_PANEL_WIDTH, 200);
			
			if (filterVisible) {
				view.filterControls.width = filterWidth;
			} else {
				view.filterControls.width = 0;
			}
		}
	
	}
}

